#include <iostream>
#include <string>
#include <math.h>
#include <fstream>
#include <boost/filesystem/path.hpp>
#include <iostream>
#include <string>
#include <stdio.h>
#include <math.h>
#include "get_arg.h"


// link with -lboost_filesystem-gcc -lboost_program_options-gcc
// program_options_helper.cpp

#define DEBUG_LEVEL 6
#include <debug_func.h>


// my functions
#include <matrix_formats.h>
#include <print_error.h>
#include <program_options_helper.h>
#include <open_stream_name_with_subscript.h>

using std::ofstream;
using std::ifstream;
using std::cout;
using std::string;
using std::vector;
using std::cerr;
using namespace program_options_helper;
namespace po = boost::program_options_lg;


//_______________________________________________________________________________________

//		process_command_line_options

//				from command line
//				Created [9/13/2001]

//_______________________________________________________________________________________


bool process_command_line_options(int argc, char* argv[], t_program_args& args)
{

	po::options_description all_args("");

	args.optional_args.add_options()
	("input_file,i", 			po::value<string>(&args.file_input)
										->set_name("FILE")
										->default_value("STDIN"),
									 "3 tab-delimited columns: 2 identifiers for the "
									 "pair and some distance measure.")
	("identifiers_only,I",		po::bool_switch(&args.identifiers_only),
									"Print identifiers only, one tab-delimited line per "
									"cluster.")
	("predefined_clusters,p", 	po::value<string>(&args.file_cluster)
										->set_name("FILE"),
									"File one tab-delimited line per cluster of "
									"identifiers.\n"
									"E.g. that produced by the following option.")
	("distinguish_instances,d",	po::value<string>(&args.distinguish_instances)
										->default_value("[ID]"),
									"The same identifier can be 'parachuted' into multiple"
									"different predefined clusters. This option allow separate "
									"instances to be distinguished. The mandatory term "
									"[ID] is the base name of the identifier and "
									"[INDEX] identifies each instance of the identifier. E.g."
									"with \"[ID]_VER_[INDEX]\", different instances of "
									"\"ENSG00123\" become ENSG00123_VER_1, ENSG00123_VER_2 "
									"etc.")
	("minimum_cluster_size,m",	po::value<unsigned>(&args.minimum_cluster_size)
										->default_value(0),
									"Discard small clusters.")
	("results_summary,R",		po::value<string>(&args.results_summary)
										->set_name("FILE"),
									"Write out summary of clustering process.")
	("#comment,#",				po::value<string>(&args.comment_letters)
										->set_name("LETTERS")
										->default_value("#"),
									"Use one of these letters to begin a "
									"commented line.");

	args.add_std_options();

	all_args.add(args.optional_args);

	po::options_description visible_args("");
	visible_args.add(args.optional_args);

	// parse command line
	po::variables_map vm;
	po::store(po::command_line_parser(argc, argv)
								.options(all_args)
								.run(), vm);
	po::notify(vm);


	if (vm.count("version"))
	{
		print_version(cerr, *argv, "1.9\n"
			"\tHistory: \n\n"
			"\tv 1.0\1"
			"Initial version\n"
			"\tv 1.1\1"
			"17-05-2005\1"
			"Fixed bug where self-links are placed in the first cluster.\1"
			"Self links are now removed and their number noted.\n"
			"\tv 1.2\1"
			"29-07-2005\1"
			"Added --identifiers option.\n"
			"\tv 1.3\1"
			"04-08-2005\1"
			"Added --predefined_clusters option allow extra pairs to be 'parachuted' "
			"into existing clusters. Code proved extremely tricky. Extensive unit test "
			"created as well.\n"
			"\tv 1.4\1"
			"26-08-2005\1"
			"Added --distinguish_instances option to allow identifiers 'parachuted' into "
			"multiple existing clusters to be labelled flexibly.\n"
			"\tv 1.5\1"
			"01-09-2005\1"
			"Added --minimum_cluster_size option to prevent small clusters being "
			"clustered into seed clusters prematurely in the first pass.\n"
			"\tv 1.6\1"
			"03-01-2006\1"
			"Bug fix for Andreas. Cluster id all off by one (leading to wrong cluster #"
			" and a zero sized final cluster). Internally, cluster_id 0 is a real "
			"'cluster' containing unclustered pairs.\n"
			"\tv 1.7\1"
			"04-01-2006\1"
			"For Andreas: Hash start comment lines. Fix bugs in handling input. "
			"Upgrade to common code for sequence pair identifiers\n"
			"\tv 1.8\1"
			"25-01-2006\1"
			"Major bug fix\1"
			"Previously, parachuting into initial clusters took sequences out of play "
			"for further clustering. This meant that initial clusters had a greatly "
			"priviledged state. This was compounded by the use of cluster size in "
			"restricting the initial cluster size above a threshold. Even if they would "
			"have qualified for privileged initial clustering, some sequences are "
			"excluded merely because they fall into smaller clusters.\1"
			"Now, after parachuting into initial clusters, sequences can still be further "
			"clustered by single linkage.\1"
			"N.B. This means that some sequences may be present in multiple clusters but "
			"that is nothing new.\n"
			"\tv 1.9\1"
			"27-03-2006\1"
			"Comments can begin with user-defined letters. Defaults to hash '#'\n"
			);
		return false;
	}
	if (vm.count("help"))
	{
		string exe_description =
							"Clusters pairs by single linkage clustering.\n"
							"Self-self links are not clustered.\n"			
							"If --identifiers_only is specified, only the identifiers "
							"are printed in one tab delimited line per cluster.\n"
							"Otherwise, the pairwise results are printed, with each cluster "
							"prefixed by an angle bracket '>' (FASTA-like). E.g.:\1"
							">cluster# 1 size= 56\n\n"
							"With --predefined_clusters, identifiers linked to predefined "
							"clusters are 'parachuted' into these before the remainder "
							"are clustered. This is not transitive: a 'parachuted' "
							"identifier will not drag along its friends unless they are "
							"independently linked to the same cluster.\n"
							"Links between items 'parachuted' into the same cluster are "
							"preserved.\n\n"
							"N.B. There are 3 levels of verbosity\1"
							"E.g. Level 2 is --verbose --verbose. Level 3 is -vvv. ";


		print_usage(cerr, string(*argv), "[OPTIONS] < file.pairs",
										visible_args, exe_description, 80);
		return false;
	}
	if (args.distinguish_instances.find("[ID]") == string::npos)
	{
		throw std::runtime_error("The --distinguish_instances option must "
								 "contain the term \"[ID]\" which is the original name "
								 "of the identifier.\n");
	}

	args.open_err_log();



	return true;
}

